package com.weifly.weistock.record.bill.impl;

import com.weifly.weistock.core.common.StockException;
import com.weifly.weistock.record.bill.BillConst;
import com.weifly.weistock.record.bill.BillParseService;
import com.weifly.weistock.record.bill.domain.StockRecordDto;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 原始对账单解析服务
 *
 * @author weifly
 * @since 2020/01/15
 */
public class BillParseServiceImpl implements BillParseService {

    private Logger log = LoggerFactory.getLogger(BillParseServiceImpl.class);

    @Override
    public List<StockRecordDto> parseRecord(File recordFile) throws IOException {
        FileInputStream fileInput = null;
        try{
            fileInput = new FileInputStream(recordFile);
            return this.parseRecord(fileInput);
        }finally {
            IOUtils.closeQuietly(fileInput);
        }
    }

    @Override
    public List<StockRecordDto> parseRecord(InputStream input) throws IOException {
        List<StockRecordDto> recordList = new ArrayList<>();
        try{
            BufferedReader reader = new BufferedReader(new InputStreamReader(input, "GBK"));
            String line = null;
            int rowIndex = 0;
            while((line=reader.readLine())!=null){
                rowIndex++;
                try{
                    if(StringUtils.isNotBlank(line)){
                        if(line.startsWith("----")){
                            continue;
                        }
                        if(line.startsWith("发生日期")){
                            continue;
                        }
                        StockRecordDto recordDto = this.parseOne(line);
                        if(recordDto!=null){
                            recordList.add(recordDto);
                        }
                    }
                }catch(Exception e){
                    String msg = "rowIndex=" + rowIndex + ", line=" + line;
                    throw new RuntimeException(msg, e);
                }
            }
        }finally {
            IOUtils.closeQuietly(input);
        }
        return recordList;
    }

    private StockRecordDto parseOne(String line){
        String[] parts = line.split("\\s+");
        if(parts==null || parts.length<2){
            log.warn("非法行, line = " + line);
            return null;
        }

        // 证券代码应为数字，如果不是数字，就不处理
        try{
            Integer.parseInt(parts[3]);
        }catch(Exception e){
            log.info("证券代码不是数字，不处理此行：" + line);
            return null;
        }

        StockRecordDto recordDto = new StockRecordDto();
        // 0 发生日期
        recordDto.setDate(parts[0]);
        // 1 成交时间
        recordDto.setTime(parts[1]);
        // 2 业务名称
        if("申购配号".equals(parts[2])){
            return null;
        }
        BillConst.BusinessName businessName = BillConst.BusinessName.getEnumByName(parts[2]);
        if(businessName==null){
            throw new StockException("业务名称不支持：" + parts[2]);
        }
        recordDto.setBusinessName(businessName);
        // 3 证券代码
        recordDto.setStockCode(parts[3]);

        // 4 证券名称 其中可能包含空格
        int nextDoubleIndex = this.nextDoubleIndex(parts, 5);
        recordDto.setStockName(this.joinString(parts, 4, nextDoubleIndex));
        // 5 成交价格
        recordDto.setTradePrice(Double.valueOf(parts[nextDoubleIndex]));
        // 6 成交数量，取绝对值
        int tradeNumber = Double.valueOf(parts[nextDoubleIndex+1]).intValue();
        recordDto.setTradeNumber(Math.abs(tradeNumber));
        // 7 成交金额
        recordDto.setTradeAmount(Double.valueOf(parts[nextDoubleIndex+2]));
        // 8 股份余额
        recordDto.setAfterNumber(Double.valueOf(parts[nextDoubleIndex+3]).intValue());
        // 9 手续费
        recordDto.setFeeService(Double.valueOf(parts[nextDoubleIndex+4]));
        // 10 印花税
        recordDto.setFeeStamp(Double.valueOf(parts[nextDoubleIndex+5]));
        // 11 过户费
        recordDto.setFeeTransfer(Double.valueOf(parts[nextDoubleIndex+6]));
        // 12 附加费
        recordDto.setFeeExtra(Double.valueOf(parts[nextDoubleIndex+7]));
        // 13 交易所清算费
        recordDto.setFeeClear(Double.valueOf(parts[nextDoubleIndex+8]));
        // 14 发生金额
        recordDto.setClearAmount(Double.valueOf(parts[nextDoubleIndex+9]));
        // 15 资金本次余额
        recordDto.setAfterAmount(Double.valueOf(parts[nextDoubleIndex+10]));
        // 16 委托编号
        recordDto.setEntrustCode(parts[nextDoubleIndex+11]);

        return recordDto;
    }

    private int nextDoubleIndex(String[] parts, int startIndex){
        for(int i=startIndex; i<parts.length; i++){
            if(parts[i].matches("(\\d+)\\.(\\d+)")){
                return i;
            }
        }
        throw new RuntimeException("not find double");
    }

    private String joinString(String[] parts, int startIndex, int endIndex){
        StringBuilder sb = new StringBuilder();
        for(int i=startIndex; i< endIndex; i++){
            sb.append(parts[i]);
        }
        return sb.toString();
    }
}
